import React, {Component} from 'react';
import {Col, Icon, Input, Row} from 'antd';
import {Badge, Modal, Toast} from 'antd-mobile';
import styles from './index.less';
import {log} from '@/utils/log-utils';
import {btnSound, playSound} from '@/utils/sounds-res';
import md5 from 'md5';
import {CACHE_BATTLE_KEY, CACHE_TOURIST_USER_KEY, CACHE_USER_KEY} from '@/utils/cache-key-utils';
import SocketEvent from '@/service/event';
import config from "@/config";
import SocketUtils from "@/service/socket";
import SubjectHeaderLayout from "@/header/father";
import AdvancedBtn from "@/button";
import {getItem, removeItem, setItem} from "@/utils/storage-utils";
import HistoryVersion from "@/pages/version";
import AdvancedSpin from "@/spinner";

/**
 * 登录界面
 */
class Login extends Component {

  constructor(props) {
    super(props);

    this.pageLogin = 'login';
    this.pageRegister = 'register';
    this.pageForgetPassword = 'forgetPassword';
    this.pageVersion = 'version';

    // 凭证登录
    this.loginTypeTicket = '0002';
    // 账号密码登录
    this.loginTypeUserPass = '0001';

    this.state = {
      text: '',
      loading: false,
      // 登录
      userId: null,
      password: null,
      // 注册
      regUserId: null,
      regUserName: null,
      regPassword: null,
      regEmail: null,
      regValidCode: null,
      // 忘记密码
      forgetUserId: null,
      forgetEmail: null,
      forgetPassword: null,
      forgetValidCode: null,

      socket: null,
      page: this.pageLogin,
      // 是否是快速登录
      isSpeedLogin: false,

      // 版本的数据
      versionData: [],
    };
  }

  componentDidMount() {
    // 只要是进入登录页，就过期掉缓存的用户对战数据
    sessionStorage.removeItem(CACHE_BATTLE_KEY);
    // 加载用户账号信息
    setTimeout(async () => {
      // 读取缓存数据
      const cacheUserJson = await getItem(CACHE_USER_KEY);
      if (cacheUserJson) {
        // 若能读取到，解析数据
        const cacheUser = JSON.parse(cacheUserJson);
        // 账号、凭证
        const userId = cacheUser.userId;
        const ticket = cacheUser.ticket;
        const length = cacheUser.pwdLength || 0;
        // 因为是假登录，所以随机模拟一个密码
        const password = SocketUtils.generateToken(length);

        this.setState({
          isSpeedLogin: true,
          userId,
          ticket: ticket,
          password: password,
        });
      }
    })

    if(!localStorage.getItem('test')) {
      Modal.alert('系统提示', `请注意，本阶段为删档测试，您的数据可能会被删除，若您无法接受，请立即退出本游戏，若您登录，则视为同意`, [
        {
          text: '知道了', onPress: () => {
            playSound(btnSound);
            localStorage.setItem('test', true);
          },
        },
      ]);
    }
  }

  /**
   * 账号密码登录
   */
  loginClick = e => {
    playSound(btnSound);
    const {userId, password, ticket, isSpeedLogin} = this.state;

    if (!userId) {
      Toast.info('请输入账号');
    } else if (!password) {
      Toast.info('请输入密码');
    } else {
      this.setState({loading: true, text: '正在登录'});
      const loginType = isSpeedLogin ? this.loginTypeTicket : this.loginTypeUserPass;
      // 请求登录
      SocketEvent.emit(this.props.socket, 'loginApi', {
        userId: userId,
        password: md5(password),
        ticket: ticket,
        type: loginType,
      }, resp => {
        log(`账号登录返回：`, resp);
        this.setState({loading: false});
        // 成功登录
        if (resp.code === 'success') {
          // 一定要用返回的账号，因为登录的时候是支持邮箱登录的
          const {ticket, userId} = resp.data || {};
          setItem(CACHE_USER_KEY, JSON.stringify({
              userId: userId,
              pwdLength: password.length,
              ticket: ticket
            },
          ));
          this.props.loginSuccess(userId);
        } else {
          Toast.show(resp.msg);
          // 凭证登录失败的时候，清除密码
          if (this.loginTypeTicket === loginType) {
            this.setState({password: null});
          }
        }
      });
    }
  };

  /**
   * 游客登录
   * @param e
   */
  touristClick = e => {
    playSound(btnSound);
    setTimeout(async () => {
      const userTicket = await getItem(CACHE_TOURIST_USER_KEY);
      if (userTicket) {
        try {
          const {userId, ticket} = JSON.parse(userTicket);
          this.setState({loading: true, text: '正在登录'});
          // 游客账号自动登录
          SocketEvent.emit(this.props.socket, 'loginApi', {
            userId: userId,
            ticket: ticket,
            type: this.loginTypeTicket,
          }, resp => {
            log(`(游客自动)账号登录返回：`, resp);
            this.setState({loading: false});
            // 登录成功
            if (resp.code === 'success') {
              const {userId} = resp.data || {};
              this.props.loginSuccess(userId);
            } else {
              Toast.show(resp.msg);
              removeItem(CACHE_TOURIST_USER_KEY);
            }
          });
        } catch (e) {
          Toast.show('登录失败，请重试');
          removeItem(CACHE_TOURIST_USER_KEY);
        }
      } else {
        const message = <ul
          style={{textAlign: "left", listStyle: 'decimal', paddingLeft: '22px', margin: '0', fontSize: '14px'}}>
          <li>游客凭证将缓存在本地</li>
          <li>游客长时间不登录将会被注销</li>
          <li>游客部分功能将受限</li>
        </ul>

        /**
         * 游客账号注册
         * @param value
         */
        const doRegisterAction = (value) => {
          SocketEvent.emit(this.props.socket, 'generateTouristApi', {
            captcha: value
          }, resp => {
            log('自动生成游客账号返回：', resp);
            if (resp.code === 'success') {
              const {userId, ticket} = resp.data || {};
              // 请求登录
              SocketEvent.emit(this.props.socket, 'loginApi', {
                userId: userId,
                ticket: ticket,
                type: this.loginTypeTicket,
              }, resp => {
                log(`(游客)账号登录返回：`, resp);
                this.setState({loading: false});
                // 登录成功
                if (resp.code === 'success') {
                  setItem(CACHE_TOURIST_USER_KEY, JSON.stringify({
                    ticket: ticket,
                    userId: userId
                  }));
                  this.props.loginSuccess(userId);
                } else {
                  Toast.show(resp.msg);
                }
              });
            } else {
              this.setState({loading: false});
              Toast.show(resp.msg);
            }
          })
        }

        /**
         * 验证码获取
         */
        const doCaptchaAction = () => {
          // 获取验证码
          SocketEvent.emit(this.props.socket, 'getCaptchaApi', {}, resp => {
            log('游客登录获取验证码返回：', resp);
            if (resp.code === 'success') {
              const {svg} = resp.data;
              Modal.prompt('安全验证', <div dangerouslySetInnerHTML={{__html: svg}}/>, [
                {text: '取消', onPress: () => playSound(btnSound)},
                {
                  text: '提交', onPress: value => {
                    playSound(btnSound);
                    if (value.length === 0) {
                      Toast.show('验证码错误');
                    } else {
                      // 带着数据一起提交
                      this.setState({loading: true, text: '正在登录'});
                      doRegisterAction(value);
                    }
                  },
                }
              ]);
            } else {
              Toast.show('验证码获取失败，请重试');
            }
          })
        }

        Modal.alert('系统提示', message, [
          {text: '再想想', onPress: () => playSound(btnSound)},
          {
            text: '知道了', onPress: () => {
              playSound(btnSound);
              doCaptchaAction();
            },
          },
        ])
      }
    })
  }

  /**
   * 注册
   * @param e
   */
  register = e => {
    playSound(btnSound);

    const {regUserId, regUserName, regPassword, regEmail, regValidCode} = this.state;
    if (!regUserId) {
      Toast.info('请输入账号');
    } else if (!(/^[0-9A-Za-z_]+$/ig.test(regUserId))) {
      Toast.info('账号仅支持字母数字下划线');
    } else if (!regUserName) {
      Toast.info('请输入昵称');
    } else if (!regPassword) {
      Toast.info('请输入密码');
    } else if (regPassword.length <= 5) {
      Toast.info('密码长度不符合要求');
    } else if (!(/[A-Za-z]+/).test(regPassword)) {
      Toast.info('密码至少包含一位字母');
    } else if (!(/[A-Za-z]+[0-9_]*$/.test(regPassword))) {
      Toast.info('密码仅支持字母、数字、下划线');
    } else if (regEmail && !(/^[A-Za-z0-9]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(regEmail))) {
      Toast.info('邮箱不符合要求');
    } else if (regEmail && !regValidCode) {
      Toast.info('请输入邮箱验证码');
    } else {
      const doRegister = (captcha) => {
        this.setState({loading: true, text: '注册中'});
        // 请求注册
        SocketEvent.emit(this.props.socket, 'registerApi', {
          userId: regUserId,
          userName: regUserName,
          password: md5(regPassword),
          email: regEmail,
          validCode: regEmail ? regValidCode : '',
          captcha: captcha,
        }, resp => {
          log(`账号注册返回：`, resp);
          this.setState({loading: false});
          // 注册成功，跳转到登录页面
          if (resp.code === 'success') {
            // 进行自动登录
            SocketEvent.emit(this.props.socket, 'loginApi', {
              userId: regUserId,
              userName: regUserName,
              password: md5(regPassword),
              type: this.loginTypeUserPass,
            }, resp => {
              log(`(自动登录)账号登录返回：`, resp);
              this.setState({loading: false});
              // 成功登录
              if (resp.code === 'success') {
                const {userId, ticket} = resp.data || {};

                setItem(CACHE_USER_KEY, JSON.stringify({
                    userId: userId,
                    pwdLength: regPassword.length,
                    ticket: ticket,
                  },
                ));
                Toast.show('已自动登录');
                this.props.loginSuccess(userId);
              } else {
                Toast.show(resp.msg);
              }
            });
          } else {
            Toast.show(resp.msg);
          }
        });
      }
      // 填写了邮箱，直接登录
      if (regEmail) {
        doRegister();
      } else {
        // 获取验证码
        SocketEvent.emit(this.props.socket, 'getCaptchaApi', {}, resp => {
          log('正式用户登录获取验证码返回：', resp);
          if (resp.code === 'success') {
            const {svg} = resp.data;
            Modal.prompt('安全验证', <div dangerouslySetInnerHTML={{__html: svg}}/>, [
              {text: '取消', onPress: () => playSound(btnSound)},
              {
                text: '提交', onPress: captcha => {
                  playSound(btnSound);
                  if (captcha.length === 0) {
                    Toast.show('验证码错误');
                  } else {
                    doRegister(captcha);
                  }
                },
              }
            ]);
          } else {
            Toast.show('验证码获取失败，请重试');
          }
        })
      }
    }
  };

  /**
   * 忘记密码提交
   * @param e
   */
  forgetPassword = e => {
    playSound(btnSound);
    const {forgetUserId, forgetEmail, forgetPassword, forgetValidCode} = this.state;

    if (!forgetUserId) {
      Toast.info('请输入账号');
    } else if (!forgetEmail) {
      Toast.info('请输入邮箱');
    } else if (!(/^[A-Za-z0-9]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(forgetEmail))) {
      Toast.info('邮箱不符合要求');
    } else if (!forgetValidCode) {
      Toast.info('请输入验证码');
    } else if (!forgetPassword) {
      Toast.info('请输入密码');
    } else if (forgetPassword.length <= 5) {
      Toast.info('密码长度不符合要求');
    } else if (!(/[A-Za-z]+/).test(forgetPassword)) {
      Toast.info('密码至少包含一位字母');
    } else if (!(/[A-Za-z]+[0-9_]*$/.test(forgetPassword))) {
      Toast.info('密码仅支持字母、数字、下划线');
    } else {
      this.setState({loading: true, text: '请求中'});
      // 请求登录
      SocketEvent.emit(this.props.socket, 'forgetPasswordApi', {
        userId: forgetUserId,
        email: forgetEmail,
        password: md5(forgetPassword),
        validCode: forgetValidCode,
      }, resp => {
        log(`找回密码返回：`, resp);
        this.setState({loading: false});
        // 成功找回密码
        if (resp.code === 'success') {
          Toast.success('您的密码已成功修改', 2, () => {
            this.setState({page: this.pageLogin});
          });
        } else {
          Toast.show(resp.msg);
        }
      });
    }
  };

  /**
   * 忘记密码发送邮件
   * @param e
   */
  handleForgetSendEmail = e => {
    playSound(btnSound);
    const {forgetUserId, forgetEmail} = this.state;
    if (!forgetUserId) {
      Toast.info('请输入账号');
    } else if (!forgetEmail) {
      Toast.info('请输入邮箱');
    } else if (!(/^[A-Za-z0-9]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(forgetEmail))) {
      Toast.info('邮箱不符合要求');
    } else {
      this.setState({loading: true, text: '正在发送邮件'});

      // 发送邮件
      SocketEvent.emit(this.props.socket, 'forgetSendValidCodeApi', {
        userId: forgetUserId,
        email: forgetEmail,
      }, resp => {
        log(`找回密码发送邮件返回：`, resp);
        this.setState({loading: false});
        if (resp.code === 'success') {
          Toast.show('邮件发送成功');
        } else if (resp.code === 'fail') {
          Toast.show(resp.msg);
        }
      });
    }
  }

  /**
   * 注册发送邮件
   */
  handleSendEmail = e => {
    playSound(btnSound);
    const {regUserId, regUserName, regPassword, regEmail} = this.state;
    if (!regUserId) {
      Toast.info('请输入账号');
    } else if (!(/^[0-9A-Za-z_]+$/ig.test(regUserId))) {
      Toast.info('账号仅支持字母和下划线');
    } else if (!regUserName) {
      Toast.info('请输入昵称');
    } else if (!regPassword) {
      Toast.info('请输入密码');
    } else if (regPassword.length <= 5) {
      Toast.info('密码长度不符合要求');
    } else if (!(/[A-Za-z]+/).test(regPassword)) {
      Toast.info('密码至少包含一位字母');
    } else if (!(/[A-Za-z]+[0-9_]*$/.test(regPassword))) {
      Toast.info('密码仅支持字母、数字、下划线');
    } else if (!regEmail || !(/^[A-Za-z0-9]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(regEmail))) {
      Toast.info('邮箱不符合要求');
    } else {
      this.setState({loading: true, text: '正在发送邮件'});

      // 发送邮件
      SocketEvent.emit(this.props.socket, 'sendValidCodeApi', {
        userId: regUserId,
        userName: regUserName,
        email: regEmail,
      }, resp => {
        log(`发送邮件返回：`, resp);
        this.setState({loading: false});
        if (resp.code === 'success') {
          Toast.show('邮件发送成功');
        } else if (resp.code === 'fail') {
          Toast.show(resp.msg);
        }
      });
    }
  };

  toVersionView = () => {
    playSound(btnSound);
    SocketEvent.emit(this.props.socket, 'versionDetailApi', {}, resp => {
      log(`获取版本详情返回：`, resp);
      this.setState({loading: false});
      if (resp.code === 'success') {
        this.setState({
          isKickOut: true,
          versionData: resp.data,
          page: this.pageVersion,
        });
      } else if (resp.code === 'fail') {
        Toast.show(resp.msg);
      }
    });
  }

  loginView = () => {
    return (
      <div className={styles.login}>
        <div className={styles.pkTitle}>
          <div title={'icon'}/>
          <span>登录</span>
        </div>

        <div className={styles.content}>
          <div className={styles.input}>
            <Input
              allowClear
              placeholder="请输入账号/邮箱"
              prefix={<Icon type={'user'}/>}
              value={this.state.userId}
              onChange={(e) => this.setState({userId: e.target.value})}/>
          </div>

          {/* 修复IOS的一个BUG，Input标签后跟一个Password时调不起中文键盘 */}
          <input style={{width: 0, height: 0, border: 'none', padding: '0', float: 'left'}}/>

          <div className={styles.input}>
            <Input.Password
              allowClear
              maxLength={32}
              minLength={6}
              placeholder="请输入密码"
              value={this.state.password}
              prefix={<Icon type={'lock'}/>}
              visibilityToggle={false}
              onFocus={e => {
                if (this.state.isSpeedLogin) {
                  this.setState({password: null, isSpeedLogin: false});
                }
              }}
              onChange={(e) => this.setState({password: e.target.value})}>
            </Input.Password>
          </div>

          <Row>
            <Col span={7}>
              <AdvancedBtn text="登录" onClick={(e) => this.loginClick(e)}/>
            </Col>
            <Col span={1}/>
            <Col span={7}>
              <AdvancedBtn
                type="normal"
                text="注册"
                onClick={e => {
                  playSound(btnSound);
                  this.setState({
                    page: this.pageRegister,
                    regUserId: '',
                    regUserName: '',
                    regPassword: '',
                    regEmail: '',
                    regValidCode: '',
                  });
                }}/>
            </Col>
            <Col span={1}/>
            <Col span={8}>
              <AdvancedBtn type="danger" text="游客登录" onClick={(e) => this.touristClick(e)}/>
            </Col>
          </Row>
        </div>
        <AdvancedSpin text={this.state.text} show={this.state.loading}/>
      </div>
    );
  };

  registerView = () => {
    const {regEmail} = this.state;

    return (
      <div className={regEmail ? styles.registerPlus : styles.register}>
        <div className={styles.pkTitle}>
          <div title={'icon'}/>
          <span>注册</span>
        </div>

        <div className={styles.content}>
          <div className={styles.input}>
            <Input
              allowClear
              placeholder="请输入账号"
              prefix={<Icon type={'user'}/>}
              maxLength={32}
              onChange={(e) => this.setState({regUserId: e.target.value})}/>
          </div>

          <div className={styles.input}>
            <Input
              allowClear
              placeholder="请输入昵称"
              prefix={<Icon type={'idcard'}/>}
              maxLength={5}
              onChange={(e) => this.setState({regUserName: e.target.value})}/>
          </div>

          {/* 修复IOS的一个BUG，Input标签后跟一个Password时调不起中文键盘 */}
          <input style={{width: 0, height: 0, border: 'none', padding: '0', float: 'left'}}/>

          <div className={styles.input}>
            <Input.Password
              allowClear
              maxLength={18}
              minLength={6}
              placeholder="请输入密码(6~18位)"
              prefix={<Icon type={'lock'}/>}
              onChange={(e) => this.setState({regPassword: e.target.value})}>
            </Input.Password>
          </div>

          <div className={styles.input}>
            <Row>
              <Col span={regEmail ? 17 : 24}>
                <Input
                  allowClear
                  placeholder="请输入邮箱(选填项)"
                  prefix={<Icon type={'mail'}/>}
                  onChange={(e) => this.setState({regEmail: e.target.value})}>
                </Input>
              </Col>
              <Col span={regEmail ? 1 : 0}/>
              <Col span={regEmail ? 6 : 0}>
                <AdvancedBtn type={'square'} text="发送" onClick={e => this.handleSendEmail(e)}/>
              </Col>
            </Row>
          </div>

          <div className={styles.input} hidden={!regEmail}>
            <Input
              allowClear
              placeholder="请输入验证码"
              prefix={<Icon type="security-scan"/>}
              onChange={(e) => this.setState({regValidCode: e.target.value})}
            />
          </div>

          <Row>
            <Col span={11}>
              <AdvancedBtn type="normal" text="注册" onClick={e => this.register(e)}/>
            </Col>
            <Col span={2}/>
            <Col span={11}>
              <AdvancedBtn
                type="danger"
                text="返回"
                onClick={e => {
                  playSound(btnSound);
                  this.setState({page: this.pageLogin});
                }}/>
            </Col>
          </Row>
        </div>
        <AdvancedSpin text={this.state.text} show={this.state.loading}/>
      </div>
    );
  };

  forgetPasswordView = () => {
    return (
      <div className={styles.register}>
        <div className={styles.pkTitle}>
          <div title={'icon'}/>
          <span>找回密码</span>
        </div>

        <div className={styles.content}>
          <div className={styles.input}>
            <Input
              allowClear
              placeholder="请输入账号"
              prefix={<Icon type={'user'}/>}
              maxLength={32}
              onChange={(e) => this.setState({forgetUserId: e.target.value})}
            />
          </div>

          <div className={styles.input}>
            <Input
              allowClear
              placeholder="请输入邮箱"
              prefix={<Icon type={'mail'}/>}
              onChange={(e) => this.setState({forgetEmail: e.target.value})}/>
          </div>

          {/* 修复IOS的一个BUG，Input标签后跟一个Password时调不起中文键盘 */}
          <input style={{width: 0, height: 0, border: 'none', padding: '0', float: 'left'}}/>

          <div className={styles.input}>
            <Row>
              <Col span={17}>
                <Input
                  allowClear
                  placeholder="请输入验证码"
                  prefix={<Icon type="security-scan"/>}
                  onChange={(e) => this.setState({forgetValidCode: e.target.value})}>
                </Input>
              </Col>
              <Col span={1}/>
              <Col span={6}>
                <AdvancedBtn type={'square'} text="发送" onClick={e => this.handleForgetSendEmail(e)}/>
              </Col>
            </Row>
          </div>

          <div className={styles.input}>
            <Input.Password
              allowClear
              maxLength={18}
              minLength={6}
              placeholder="请输入新密码(6~18位)"
              prefix={<Icon type={'lock'}/>}
              onChange={(e) => this.setState({forgetPassword: e.target.value})}>
            </Input.Password>
          </div>

          <Row>
            <Col span={11}>
              <AdvancedBtn type="normal" text="确定" onClick={e => this.forgetPassword(e)}/>
            </Col>
            <Col span={2}/>
            <Col span={11}>
              <AdvancedBtn
                type="danger"
                text="返回"
                onClick={e => {
                  playSound(btnSound);
                  this.setState({page: this.pageLogin});
                }}/>
            </Col>
          </Row>
        </div>
        <AdvancedSpin text={this.state.text} show={this.state.loading}/>
      </div>
    );
  };

  render() {
    const {page} = this.state;
    return (
      <React.Fragment>
        <div className={styles.header} hidden={page !== this.pageLogin}>
          <SubjectHeaderLayout text={'五子棋'}/>
          <div className={styles.tips}>
            {/*<span>适当游戏益脑，沉迷游戏伤身</span>*/}
            {/*<span>合理安排时间，享受健康生活</span>*/}
            <span className={styles.content}>Bug反馈：<span className={styles.num}>305 581 057</span>(群)</span>
          </div>
        </div>
        <div className={styles.floor} hidden={page !== this.pageLogin}>
          <Badge>
            <span className={styles.item} onClick={e => {
              playSound(btnSound);
              this.setState({page: this.pageForgetPassword});
            }}>忘记密码</span>
          </Badge>
          |
          {/*<Badge dot>*/}
          {/*  <span className={styles.item} onClick={e => {*/}
          {/*    playSound(btnSound);*/}
          {/*    router.push('ai');*/}
          {/*  }}>体验AI</span>*/}
          {/*</Badge>*/}
          {/*|*/}
          <Badge dot>
            <span className={styles.item} onClick={this.toVersionView}>v{config.version}</span>
          </Badge>
        </div>
        {page === this.pageLogin && this.loginView()}
        {page === this.pageRegister && this.registerView()}
        {page === this.pageForgetPassword && this.forgetPasswordView()}
        {page === this.pageVersion &&
        <HistoryVersion versionData={this.state.versionData} goBack={() => this.setState({page: this.pageLogin})}/>}
      </React.Fragment>
    );
  }
}

export default Login;
